/*----------------------------------------------------------------------------
 * Copyright (c) <2019-2020>, <Huawei Technologies Co., Ltd>
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice, this list of
 * conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
 * of conditions and the following disclaimer in the documentation and/or other materials
 * provided with the distribution.
 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
 * to endorse or promote products derived from this software without specific prior written
 * permission.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *---------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
 * Notice of Export Control Law
 * ===============================================
 * Huawei OMIP(belong to OMSIS) may be subject to applicable export control laws and regulations, which might
 * include those applicable to Huawei LiteOS of U.S. and the country in which you are located.
 * Import, export and usage of Huawei LiteOS in any manner by you shall be in compliance with such
 * applicable export control laws and regulations.
 *---------------------------------------------------------------------------*/
#ifndef __OMIP_H_
#define __OMIP_H_

#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "omip_cmd.h"
#include "omip_conf.h"
#include "omip_log.h"
#include "osal.h"

#define OMIP_VER "omip1.7.0"
#define OMIP_MAJOR 1
#define OMIP_MINOR 7

#define OMIP_START   0xC2 //frame start
#define OMIP_END     0xC0 //frame end
#define OMIP_ESC     0xDB //frame escape
#define OMIP_ESC_START 0xDA
#define OMIP_ESC_END 0xDC //transposed frame OMIP_END
#define OMIP_ESC_ESC 0xDD //transposed Frame Escape

#define OMIP_USER_DATA_MAX_LEN (OMIP_FRM_MAX_LEN - 12) // only user data

#define OMIP_UART_SKB_NUM   OMIP_UART_RCV_BUFF/OMIP_FRM_MAX_LEN

//flags
#define OMIP_LAST_FRAME        (1 << 7)
#define OMIP_FRAME_RETRANS     (1 << 6)
#define OMIP_RELAY_VALID       (1 << 5)

//channel open state
#define OMIP_CHANNEL_CLOESED   0
#define OMIP_CHANNEL_OPENED    1



//error code
#define OMIP_OK                   (int)0
#define OMIP_VC_INVALID           (int)-1
#define OMIP_BUF_FULL             (int)-2
#define OMIP_QOS_INVALID          (int)-3
#define OMIP_MALLOC_FAILED        (int)-4
#define OMIP_POINTER_NULL         (int)-5
#define OMIP_PARAS_INVALID        (int)-6
#define OMIP_VC_NOT_OPENED        (int)-8
#define OMIP_NOT_IN_WINDOW        (int)-9  //qos2
#define OMIP_LENGTH_INVALID       (int)-11
#define OMIP_READ_QUEUE_ERROR     (int)-12
#define OMIP_CT_INVALID           (int)-100
#define OMIP_QUEUE_RECV_TIMEOUT   (int)-200

//below only use in inner
#define OMIP_CRC_ERROR            (int)-14
#define OMIP_NO_RESOURCE          (int)-15
#define OMIP_FRAME_NOT_EXP        (int)-16
#define OMIP_RECV_NAK             (int)-17
#define OMIP_TIMEOUT              (int)-18
#define OMIP_ERROR_UNKNOWN        (int)-19
#define OMIP_NULL_POINTER         (int)-20
#define OMIP_QUEUE_SEND_FAILED    (int)-22
#define OMIP_QUEUE_RECV_FAILED    (int)-23
#define OMIP_QUEUE_CREATE_QUEUE_FAILED    (int)-24
#define OMIP_QUEUE_FULL                   (int)-25
#define OMIP_QUEUE_EXSITED                (int)-26
#define OMIP_QUEUE_INDEX_INVALID          (int)-27
#define OMIP_CREATE_MUTEX_FAILED          (int)-28
#define OMIP_APP_NAME_INVALID             (int)-29
#define OMIP_CREATE_SEMAPHORE_FAILED      (int)-30
#define OMIP_INDEX_INVALID                (int)-31
#define OMIP_MUTEX_LOCK_FAILED            (int)-32

#define OMIP_NOT_NEED_RELAY   0
#define OMIP_NEED_RELAY       1  

// file transfer result

#define OMIP_FILE_OK            0
#define OMIP_UNKNOWN_ERROR      1
#define OMIP_INVALID_PARA       4
#define OMIP_INVALID_FORMAT     5
#define OMIP_FILE_NO_SPACE      22
#define OMIP_FILE_SIZE_ERROR    25
#define OMIP_FILE_MNGR_BUF     	1024

typedef enum {
    OMIP_WORK_CONTROLER,
    OMIP_WORK_MODULE,
    OMIP_WORK_PROXY,
    OMIP_WORK_INVALID,
}omip_workmode;

typedef enum {
    OMIP_QOS_0,//send once,no ack
    OMIP_QOS_1,//receive at least once
    OMIP_QOS_2,//receive exactly once
    OMIP_QOS_MAX,
}omip_qos_level;

enum omip_content_format {
    OMIP_CONTENT_FORMAT_BINARY,
    OMIP_CONTENT_FORMAT_JSON,
    OMIP_CONTENT_FORMAT_ASN1_UPER,
    OMIP_CONTENT_FORMAT_ASN1_DER,    
    OMIP_CONTENT_FORMAT_INVALID,
};

enum omip_send_gid_state {
    OMIP_GID_FREE,
    OMIP_GID_PACKET_NO_SENT,    
    OMIP_GID_PACKET_WAIT_ACK,
    OMIP_GID_PACKET_RECV_ACK,
};

enum omip_recv_gid_state {
    OMIP_GID_NO_PACKET,
    OMIP_GID_PACKET_WAITING,    
    OMIP_GID_PACKET_SENT2USER,
};

enum omip_reassemble_state {
    OMIP_REASSEMBLE_NONE,
    OMIP_REASSEMBLE_ONGOING,
    OMIP_REASSEMBLE_DONE,
};

#define OMIP_CONNECT_STATE_INIT            (unsigned char)0
#define OMIP_CONNECT_STATE_SENDREQ         (unsigned char)1
#define OMIP_CONNECT_STATE_SENDREQ_RECVACK (unsigned char)2
#define OMIP_CONNECT_STATE_SENDREQ_RECVREQ (unsigned char)3
#define OMIP_CONNECT_STATE_DONE_OK         (unsigned char)4
#define OMIP_CONNECT_STATE_DOWN_LEVEL      (unsigned char)5



#define APP_NAME_LENGTH (33)

struct omip_config_paras_tag {
    unsigned short task_pri;
    unsigned int stack_size;
};
typedef struct omip_config_paras_tag omip_config_paras;

typedef struct  {
    short retrans;//if retrans >= 0,retrans times, if retrans < 0, for ever retrans
    short rtime;  //if rtime == 0,then send again
    unsigned short retran_times;
    unsigned int send_cur_time;
}omip_timeout_para;

struct omip_buf_list_tag {
    struct omip_buf_list_tag *next;
    unsigned char *payload;//max is 512
    unsigned short len;
    unsigned short pad;
};
typedef struct omip_buf_list_tag omip_buf_list;

struct omip_send_list_tag {
    struct omip_send_list_tag *next;
    omip_timeout_para tmo;
    unsigned char vc;
    unsigned char ct;
    unsigned char relay_flag;
    unsigned char relay_vc;
    unsigned char sid;
    unsigned char fmt;
    unsigned short cmd;
    unsigned int tlen;
    omip_buf_list pbuf;
    unsigned char ext_io_flag;
};

typedef struct
{
    unsigned short pos;
    unsigned short len;
}omip_frame_postion;

typedef void (*omip_inject_send)(unsigned char *data, unsigned short len, int io_id);
typedef void (*omip_inject_recv_byte)(unsigned char data, int io_id);

typedef struct omip_io_paras_tag
{
    unsigned short        write_index;    //the index of buf to be write when receive data
    unsigned short        is_ESC;   //1:the last receive data is OMIP_ESC
    unsigned short        is_receive_frame_head;
    unsigned short        cur_frame_len;
    unsigned short skb_write_index;
    unsigned short skb_read_index;
    omip_frame_postion skb_buf[OMIP_UART_SKB_NUM];
    unsigned char      *rcvbuf;
    unsigned int       rcvbuf_len;
    omip_inject_send      inject_send;
    omip_inject_recv_byte inject_recv_byte;
}omip_io_paras;

typedef struct {
    unsigned char result;
    unsigned char exp_sid;
    unsigned char recv_cap;
    unsigned char exp_fid;//not used now,maybe used later
}omip_ack_info;


struct omip_frame_data_list{
    unsigned char    vc;
    unsigned char    ct;
    unsigned char    relay_vc;
    unsigned char    sid;
    unsigned char    fid;
    unsigned char    last_frame;
    unsigned char    retrans;
    unsigned char    relay_flag;
    omip_frame_type  ftype;
    unsigned short   len;
    unsigned char    *origin_frame;    //for relay to next destination in proxy mode
    unsigned short   origin_frame_len;
    union {
        struct {
            unsigned short cmd;
            unsigned char  data[OMIP_USER_DATA_MAX_LEN];
        }req;
        omip_ack_info ack;
    }u;
    struct omip_frame_data_list *next;
};
typedef struct omip_frame_data_list omip_frame_data_list;

struct omip_recv_assemble_tag{
    unsigned char used;
    unsigned char vc;
    unsigned char ct;
    unsigned char sid;
    unsigned char exp_fnum;
    unsigned int ctime;
    unsigned short cmd;
    unsigned int tlen;
    unsigned char relay_flag; //wether or not relay by proxy
    unsigned char relay_vc;    //realy virtual channel,not used in p2p
    omip_frame_data_list *next;
};

typedef struct omip_send_list_tag omip_send_list;
typedef struct omip_recv_assemble_tag omip_recv_assemble;
typedef int (*omip_recv_fn)(void *arg, void *data, unsigned short len);
typedef struct {
    unsigned char used;
    unsigned char sid;
    unsigned char exp_sid; //expect group id,only use when level == OMIP_QOS_1
    unsigned char peer_exp_sid;// peer expect gid,only use when level == OMIP_QOS_1
    omip_qos_level level;//qos
    unsigned char connect_state;
    unsigned short unsent_num;
    unsigned short unack_num;
    unsigned char last_sid_send2user;
    unsigned char support_auth;
    unsigned short sid_local_overflow_num;//local sid overflow num
    unsigned short sid_remote_overflow_num;//peer sid overflow num,get from shakehand
    omip_send_list *head_unsent;
    omip_send_list *head_unack;
    osal_queue_t recv_queue;
    omip_recv_fn recv_cb;
    omip_recv_assemble assemble_head[OMIP_MAX_ASSEMBLE_NUM];
    volatile unsigned short assemble_num;
    /** user-supplied argument for the recv callback */
    unsigned char recv_sid_flag[OMIP_SID_MAX+1];//two bit reprent one gid
    unsigned char send_sid_flag[OMIP_SID_MAX+1];//two bit reprent one gid
    osal_mutex_t  user_send_mutex;//only one user can send slip frame concurrent
    void *recv_arg;
    unsigned char send_left_window;  //used by qos2
    unsigned char send_right_window; //used by qos2
    unsigned char recv_left_window;  //used by qos2
    unsigned char recv_right_window; //used by qos2 
    unsigned int recv_not_expt_msg;
    void *app_s;
}omip_sock;


struct omip_context_tag {
    unsigned int   ctime;
    omip_io_paras *io_p[OMIP_SUPPORT_MAX_PYS_DEV_NUM];
    unsigned int cur_io_p_id;
    omip_sock     *sock;
    unsigned char send_frame_buf[OMIP_FRM_MAX_LEN];
    //unsigned short peer_capacity;
    void          *work_handle;
    void          *observe_handle;
    osal_mutex_t  active_vc_mutex;
    unsigned char active_vc[OMIP_VC_CHANNEL_TOTAL];
    unsigned char active_vc_num;
    unsigned char cur_active_pos;
    omip_workmode workmode;
    osal_semp_t  io_tx_rx_sem;//if a frame has been written to the receive buffer, then active it
};

struct omip_config_info {
    unsigned int magic;
    unsigned short major;
    unsigned short minor;
    unsigned char qos;
    unsigned char reserved[1];
    unsigned short sid_overflow_num;
};

struct omip_stat_info {
    unsigned int sendacknum;
    unsigned int send_failed;
    unsigned int recvacknum;
    unsigned int recvacknum_good;
    unsigned int recvacknum_bad;
    unsigned int recvacknum_not_found;
    unsigned int sendreqnum;
    unsigned int freeitemnum;
    unsigned int recvreqnum;
    unsigned int recvebytesnum;
    unsigned int recvemsgsnum;
    unsigned int max_retrans;
    unsigned int max_delay;
};

/*interface 1.0 */
int omip_api_open_vc(unsigned char vc, omip_qos_level level, const char *app_name);
void omip_api_close(unsigned char vc, const char *app_name);

int omip_api_send(unsigned char vc, unsigned char ct, unsigned short cmd, unsigned char *data, unsigned int len);
int omip_api_recv(unsigned char vc, unsigned char *ct, unsigned short *cmd, unsigned char *data, unsigned int len);

/*---------------------------------------------------------------------------------------------------------------*/
/*interface 2.0*/
typedef struct omip_transaction_tag {
    unsigned char vc;          //virtual channel
    unsigned char ctf;         //content format
    unsigned char relay_flag; //wether or not relay by proxy
    unsigned char relay_vc;    //realy virtual channel,not used in p2p
    unsigned short cmd;        //command
    unsigned char *data;       //user data;
    unsigned int len;          //user data len;
#define OMIP_WAIT_FOREVER  0xFFFFFFFF
#define OMIP_SEND_DEFAULT  (1000*2)
#define OMIP_RECV_DEFAULT  (1000*10)
    unsigned int timeout;      //timeout, return failed,ms,if 0xFFFFFFFF,wait for ever
#define OMIP_ENCODE_DEFAULT   0   //default 
#define OMIP_NOT_ENCODE       1   //not need omip encode,such as set ble name
#define OMIP_ENCODE_EXT       2   //need omip encode
    unsigned int ext_io_flag;//默认为0,蓝牙命令为1，蓝牙数据为2
}omip_transaction;

typedef struct omip_shakehand_sync_tag {
    unsigned char vc;
    unsigned char relay_flag; //wether or not relay by proxy
    unsigned char relay_vc;    //realy virtual channel,not used in p2p
    unsigned char reconnect_flag;
    unsigned char *data;
    unsigned int len;
    unsigned int timeout;      //timeout, return failed,ms,if 0xFFFFFFFF,wait for ever
}omip_shakehand_sync;

int omip_set_workmode(omip_workmode mode);
int omip_open_vc(unsigned char vc, omip_qos_level level, const char *app_name, unsigned char support_auth);
int omip_close_vc(unsigned char vc, const char *app_name);
int omip_send(omip_transaction *ts);
int omip_recv(omip_transaction *ts);

int omip_shakehand(omip_shakehand_sync *sync);
int omip_qos_downlevel(unsigned char vc);
int omip_set_inject_func(int io_id, omip_inject_send send, omip_inject_recv_byte recv_byte);
int omip_set_app_s(unsigned char vc, void *app_s);

/*---------------------------------------------------------------------------------------------------------------*/
void* omip_malloc(unsigned int size);
void omip_free(void* addr);
void omip_receive_byte(unsigned char data, int io_id);// receive one byte through UART serial port
int omip_module_install(omip_config_paras *para);
void omip_module_uninstall(void);
struct omip_context_tag  *omip_get_context(void);


#endif /* HLINK_SLIP_H_ */

